#pragma once

#include "AssetPath.h"
#include "AssetHead.h"

#include "Async/PackagedTask.h"
#include "Path/Path.h"

#include "Containers/Delegate.h"

#include "AssetPackage.h"

#include <mutex>




class WHENGINE_API CAssetReader
{
public:
    CAssetReader() = default;
    ~CAssetReader() = default;

    //create a async task to read asset file into memory
    //return a packaged task, you can get the result by calling PackagedTask::ThenInMainThread
    virtual std::shared_ptr<CPackagedTask<TVector<uint8_t>>>
        CreateAsyncReadTask(const SAssetPath& InAssetPath,bool bOnlyAssetHeader); 

    virtual std::shared_ptr<CPackagedTask<TVector<uint8_t>>>
        CreateAsyncReadTask(
             const CString& InPackageName
            , const CString& InAssetPathInPackage
            , const CString& InAssetName
            , bool bOnlyAssetHeader);

    virtual std::shared_ptr<CPackagedTask<TVector<uint8_t>>>
        CreateAsyncReadTask(
            const SPath& InAssetFilePath
            , bool bOnlyAssetHeader);

    //create a async task to find all asset packages in directory
    // virtual std::shared_ptr<CPackagedTask<TVector<SAssetPackage>>>
    //     CreateAsyncFindAllAssetPackagesTask(const SPath & InFolder);

    //replace asset path in other asset file which reference the asset
    //return the new asset path
    // virtual std::shared_ptr<CPackagedTask<SAssetPath>>
    //     CreateAsyncRenameAssetTask(
    //         const SAssetPath& InAsset
    //         ,const CString& InNewPackageName
    //         ,const CString& InAssetPathInPackage
    //         ,const CString& InNewAssetName
    //     );
 
    //start a async task to find directoy or asset file in the search folders
    //@InPackageName: the package  to search
    //@InQueryFolderRelativePath: the folder to search, relative to the package folder ,
    //for example, if the package folder is "Content/MyPackage", and the InQueryFolderRelativePath is "MyFolder"
    //, then the query folder is "Content/MyPackage/MyFolder"
    //the InQueryFolderRelativePath is shown in content widget, may be not a real folder in disk
    virtual void
        AsyncFindItemsInFolderTask(const CString& InPackageName
            , const TVector<CString>& InQueryFolderRelativePath
            , const TDelegate<void,CString /*Directory Name*/> & OnFoundDirectoy 
            , const TDelegate<void
                ,const SAssetPath &/*Asset Path*/
                ,const SAssetHead &
                ,TSharedObjectPtr<RTexture2D>> & OnFoundAssetFile
            , const TDelegate<bool> CanContinue /*if return false, stop find*/
            , const TDelegate<void> & OnFinished =nullptr
            );

    //find all  asset file match Class in the search packages
    void AsyncFindItemsMatchClass(CClass* InClass
        , const TVector<SAssetPackage>& InPackages
        , const TDelegate<void,const SAssetPath &/*Asset Path*/,const SAssetHead &,TSharedObjectPtr<RTexture2D>> & OnFoundAssetFile
        , const TDelegate<bool> CanContinue /*if return false, stop find*/
        , const TDelegate<void> & OnFinished =nullptr
    );

    //find first asset file match Class in the search packages
    void AsyncFindFirstItemMatchClass(CClass* InClass
        , const TVector<SAssetPackage>& InPackages
        , const TDelegate<void,const SAssetPath &,const SAssetHead &,TSharedObjectPtr<RTexture2D>> & OnFoundAssetFile
        , const TDelegate<void> & OnFindNothing =nullptr
    );

    struct SAssetPathAndHead
    {
        SAssetPath AssetPath;
        SAssetHead AssetHead;

        SPath AssetFilePath;
    };

    /// @brief 
    /// @param InPackage 
    /// @param OnFoundAssetFile callback when found asset file, only invoke in main thread
    /// @param InLastWriteTime  last write time of the asset file
    /// @param OnFinished  callback when finished, only invoke in main thread
    void AsyncFindAllAssetInPackaged(
        const SAssetPackage& InPackage
        , const TDelegate<void
            ,const TVector<SAssetPathAndHead> &
        > & OnFoundAssetFile 
        , const TDelegate<void> & OnFinished 
        , std::chrono::file_clock::time_point InLastWriteTime =std::chrono::file_clock::time_point::min()
    );

protected:

};